
#INCLUDE "./defVarComunesMusica.bas"
#DEFINE AYR 65533 
#DEFINE AYV 49149
DIM timersAy(3)  AS UINTEGER                                              
DIM canal AS UBYTE   'tonoLow, tonoHigh ,


DIM duracionCanal(3) AS UINTEGER
DIM posicionNotas(3) AS UINTEGER
DIM cantNotasCanal(3) AS UINTEGER
DIM ultimaNotaRep(3,2) AS UBYTE

SUB activaChipAy()
    OUT AYR,7           'activa channel a, b y c
    OUT AYV,BIN 11111000   'activa channel a
END SUB
SUB estableceVolumenCanalesAy(a as UBYTE, b as UBYTE, c as ubyte)   
    OUT AYR,8           
    OUT AYV,a
    OUT AYR,9          
    OUT AYV,b
    OUT AYR,10           
    OUT AYV,c            
END SUB

SUB silenciarCanalesAy()
    'lo unico que hago es silenciar cada canal
    FOR r = 0 TO 5
        OUT AYR, r : OUT AYV, 0
    NEXT r
END  SUB
   
SUB inicializaReproduccionAy()
    cantNotasCanal(1)  = peek (UINTEGER,RepAyAddress)
    cantNotasCanal(2)  = peek (UINTEGER,RepAyAddress+2)
    cantNotasCanal(3)  = peek (UINTEGER,RepAyAddress+4)
    posicionNotas(1)   = RepAyAddress + 6 
    posicionNotas(2)   = posicionNotas(1) + (cantNotasCanal(1) *5) 
    posicionNotas(3)   = posicionNotas(2) + (cantNotasCanal(2) *5)
    timersAy(1) = peek (uinteger, 23672)  'peek (23672)  
    timersAy(2) = peek (uinteger, 23672)   'peek (23672)   
    timersAy(3) = peek (uinteger, 23672)   'peek (23672) 


'sumo una unidad a cada canal , dado que la primera entrada que se da en reachedTime , no es una nota real , por eso
'sumo una a cada canal para que se procesen todas las notas.
    FOR n = 1 TO 3
        cantNotasCanal(n) = cantNotasCanal(n) +1
    NEXT n
END SUB


SUB muestraInfoMelodia()
        CLS 
        PRINT "cant Notas Canal 1: "; cantNotasCanal(1) -1
        PRINT "cant Notas Canal 2: "; cantNotasCanal(2) -1
        PRINT "cant Notas Canal 3: "; cantNotasCanal(3) -1
        PRINT "Pos Notas Canal 1: ";  posicionNotas(1)
        PRINT "Pos Notas Canal 2: ";  posicionNotas(2)
        PRINT "Pos Notas Canal 3: ";  posicionNotas(3)
        PRINT "PRESIONE W PARA REPRODUCIR"
        PRINT "PRESIONE E PARA PARAR"
        PRINT "PRESIONE R PARA PAUSAR"
END SUB


FUNCTION determinaDifTiempo(nroTimer as UBYTE) AS uinteger
    'la variable de sistema frames , en su bit menos significativo se ubica
    'en la posicion 23672.
   DIM time AS UINTEGER = peek (uinteger, 23672) 
   DIM difTime as UINTEGER
   IF timersAy(nroTimer) <= time then
        
        difTime = time - timersAy(nroTimer)                        
   ELSE
        difTime = (65535 - timersAy(nroTimer) ) + time   
   END IF
   RETURN  difTime
END FUNCTION



/'
 INPUTS
 * nroTimer  cada nro de timer esta asociado a una evento determinado
 * ticks  cantidad de retraso que se quiere incluir medido en refrescos de pantalla
 Es decir cada ticks = 20 mls
 OUTPUTS
 * retorna boolean , 1 si se alcanzo la cantidad de ticks desde la ultima testeada y 0 si todavia no
 FUNCIONAMIENTO
  Cada vez que se llama esta funcion se mide cuanto tiempo paso desde la vez anterior que fue llamada y se compara con un valor fijo, si el tiempo que paso es superior a ese valor fijo devuelve 1 sino devuelve 0. Si devuelve 1 tambien actualiza el valor del timer . 
 '/
 FUNCTION reachedTimeAy(nroTimer as ubyte,ticks as uinteger) AS ubyte     
        DIM difTime AS UINTEGER
        difTime = determinaDifTiempo(nroTimer)
        IF difTime >= ticks then 
            timersAy(nroTimer) = peek (uinteger, 23672) 
            RETURN 1
        ELSE
            RETURN 0
        END IF
        
END FUNCTION




FUNCTION obtieneRegistroLowNoteDelCanal(canal as ubyte) AS ubyte
    IF canal = 1 then
        RETURN 0
    ELSE IF canal = 2 then
        RETURN 2
    ELSE 
        RETURN 4
    END IF       
END FUNCTION



SUB procesaUnaNota() 
  IF statusRepAy = 1 then
    IF cantNotasCanal(1)+cantNotasCanal(2) + cantNotasCanal(3) <> 0 then
        FOR canal =1 TO 3   
            IF cantNotasCanal(canal) > 0 then    
                IF reachedTimeAy(canal,duracionCanal(canal))    'canal
                    cargaProximaNota()            
                END IF
            END IF
        NEXT canal
        melodiaTerminada =0
    ELSE     
        IF tipoRepAy = 1 then
            inicializaReproduccionAy()
        ELSE
            changeStatusRepAy(2)
        END IF
        melodiaTerminada =1
    END IF  
  END IF
END SUB       

SUB changeStatusRepAy(status as ubyte)
  DIM oldStatus AS UBYTE =statusRepAy
  DIM tonoLow, tonoHigh,registroLowNote AS UBYTE
  statusRepAy = status
  'tocando
  IF statusRepAy = 1 then  
   'si el status anterior era parado, entonces recargo todos los datos necesarios para reproduccion
    IF oldStatus = 2 then
        FOR n = 1 TO 3
          duracionCanal(n) = 0
        NEXT n    
        inicializaReproduccionAy() 
    'si el status anterior era pausado, entonces recargo los datos necesarios de reproduccion 
    ELSE IF oldStatus = 0 then
       FOR n = 1 TO 3
         timersAy(n) = peek (uinteger, 23672)
         registroLowNote  = obtieneRegistroLowNoteDelCanal(canal)
         OUT AYR,registroLowNote    'set the note value Channel 
         OUT AYV,ultimaNotaRep(n,1)            'set the note value
         OUT AYR,registroLowNote+1  'set the note value Channel A High
         OUT AYV,ultimaNotaRep(n,2)            'set the note value     
       NEXT n   
    END IF
  ELSE IF statusRepAy = 0 then
    silenciarCanalesAy()
    FOR n = 1 TO 3
        IF duracionCanal(n) <> 0 then
            duracionCanal(n) = duracionCanal(n) - determinaDifTiempo(n)
        END IF
    NEXT n
    
  ELSE IF statusRepAy = 2 then   
    silenciarCanalesAy() 
  END IF
END SUB

SUB cargaProximaNota()  
    DIM tonoHigh,tonoLow,registroLowNote AS UBYTE
   
    'SetSlot3(4)
    'lo que imprimo son los datos de la nota que acaba de terminar.
    #ifdef debug_musica_activo
        PRINT canal ; " " ;cantNotasCanal(canal); " tonos " ;tonoHigh; " ";  _ 
        tonoLow  ;"st"; statusRepAy 
    #endif
    'si esta en 1 significa que acaba de finalizar la ejecucion de la utima nota
    'con lo cual no debe tomarse mas datos , simplemente dejar las notas en 0
    registroLowNote  = obtieneRegistroLowNoteDelCanal(canal)
    IF cantNotasCanal(canal) > 1
        tonoHigh             = peek(posicionNotas(canal)+1) 
        tonoLow              = peek(posicionNotas(canal)+2)
        duracionCanal(canal) = peek(uinteger,posicionNotas(canal)+3)
        'registroLowNote  = obtieneRegistroLowNoteDelCanal(canal)
        OUT AYR,registroLowNote    'set the note value Channel 
        OUT AYV,tonoLow            'set the note value
        OUT AYR,registroLowNote+1  'set the note value Channel A High
        OUT AYV,tonoHigh           'set the note value
        'deja el puntero al inicio de la proxima nota 
        posicionNotas(canal) = posicionNotas(canal) +5
        'guardo la ultima nota reproducida por canal, se necesita para reproducir despues de pausa
        ultimaNotaRep(canal,1) = tonoLow
        ultimaNotaRep(canal,2) = tonoHigh
        
     ELSE
        OUT AYR,registroLowNote    'set the note value Channel 
        OUT AYV,0            'set the note value
        OUT AYR,registroLowNote+1  'set the note value Channel A High
        OUT AYV,0           'set the note value
     END if
     
    cantNotasCanal(canal) = cantNotasCanal(canal) -1 
'    'SetSlot3(0)  
END SUB
